﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tao.OpenGl;

namespace CutAways.Geometry
{
	class Line
	{
		private Vector a, b;

		public Vector A
		{
			get { return a; }
			set { a = value; }
		}

		public Vector B
		{
			get { return b; }
			set { b = value; }
		}

		public Line(Vector a, Vector b)
		{
			this.a = a;
			this.b = b;
		}

		public bool IntersectsLineWithLineSegment(Line x, out Vector intersection, out float rayParam)
		{
			Vector p1 = this.a;
			Vector p2 = this.b;
			Vector p3 = x.a;
			Vector p4 = x.b;

			float denominator = (p4.Y - p3.Y) * (p2.X - p1.X) - (p4.X - p3.X) * (p2.Y - p1.Y);
			float nominatorA = (p4.X - p3.X) * (p1.Y - p3.Y) - (p4.Y - p3.Y) * (p1.X - p3.X);
			float nominatorB = (p2.X - p1.X) * (p1.Y - p3.Y) - (p2.Y - p1.Y) * (p1.X - p3.X);

			

			if (denominator == 0f) // are parallel
			{
				//if (nominatorA == 0f) // are coincident
				//	...;
				intersection = new Vector(float.NaN, float.NaN, float.NaN);
				rayParam = float.PositiveInfinity;
				return false;
			}

			rayParam = nominatorA / denominator;
			float lineParam = nominatorB / denominator;

			intersection = p1 + (p2 - p1) * rayParam;

			return lineParam >= 0f && lineParam <= 1f;
		}

		public Vector[] GetIntersectionsWithCylinderAndItsFloors(Vector cylinderFront, Vector cylinderBack, float cylinderRadius)
		{
			Vector M0 = Vector.Norm(this.b - this.a);
			Vector Mc = Vector.Norm(cylinderBack - cylinderFront);
			Vector P0c = this.a - cylinderFront;
			
			// at^2 + bt + c = 0

			float aParam = 1f - Vector.SQR(Vector.Dot(M0, Mc));
			float bParam = 2f * (Vector.Dot(P0c, M0) - Vector.Dot(P0c, Mc) * Vector.Dot(M0, Mc));
			float cParam = Vector.Dot(P0c, P0c) - Vector.SQR(Vector.Dot(P0c, Mc)) - Vector.SQR(cylinderRadius);

			// D = b^2 - 4ac
			float diskriminant = Vector.SQR(bParam) - 4f * aParam * cParam;

			List<Vector> results = new List<Vector>();

			// pokud je diskriminant nezaporny tak existuji pruseciky s valcovou plochou
			if (diskriminant >= 0f)
			{
				float sqrtD = (float)Math.Sqrt(diskriminant);
				float t1 = (-bParam + sqrtD) / (2f * aParam);
				float t2 = (-bParam - sqrtD) / (2f * aParam);

				Interval lineInterval = new Interval(0f, (this.b - this.a).GetLength());

				if (lineInterval.Contains(t1))
					results.Add(this.a + M0 * t1);
				if (diskriminant > 0f && lineInterval.Contains(t2))
					results.Add(this.a + M0 * t2);
			}

			// ted jeste spocitat pruseciky s podstavami
			Quad front = new Quad(cylinderFront, Mc, cylinderRadius);
			Quad back = new Quad(cylinderBack, Mc, cylinderRadius);
			Vector intersection, parametres;

			if (front.IntersectsWithLine(this.a, this.b, out intersection, out parametres) && (intersection - cylinderFront).GetLength() < cylinderRadius)
				results.Add(intersection);
			if (back.IntersectsWithLine(this.a, this.b, out intersection, out parametres) && (intersection - cylinderBack).GetLength() < cylinderRadius)
				results.Add(intersection);

			return results.ToArray();
		}
	}
}
